Skip to content

Implement SpectrumSource::iter_chromatograms so TIC/BPC chromatograms reach mzML output#18

Open
Nabejo wants to merge 1 commit into
Sigilweaver:mainfrom
Nabejo:iter-chromatograms-openaraw
Open

Implement SpectrumSource::iter_chromatograms so TIC/BPC chromatograms reach mzML output#18
Nabejo wants to merge 1 commit into
Sigilweaver:mainfrom
Nabejo:iter-chromatograms-openaraw

Conversation

@Nabejo

@Nabejo Nabejo commented Jul 19, 2026

Copy link
Copy Markdown
Contributor

Fixes #17

What this does

Overrides the SpectrumSource::iter_chromatograms trait default on Reader (the previous fall-through to the empty default meant no chromatograms reached mzML output). It emits two run-level summary chromatograms:

  • TIC - MS:1000235 "total ion current chromatogram"
  • BPC - MS:1000628 "basepeak chromatogram"

Both are aggregated from data OpenARaw already decodes: for each MS1 scan, TIC is the sum of the decoded intensities and BPC is the most intense point, computed via SpectrumRecord::effective_tic() / effective_base_peak(). This does no new binary parsing, and keeps the traces self-consistent with the spectra actually emitted for the run. Retention time is already carried in seconds by SpectrumRecord, so it is only narrowed to f32 for ChromatogramRecord::time_sec.

Only MS1 scans contribute, since that is what the two CV terms describe and mixing interleaved MS2 scans would produce a non-chromatographic, RT-duplicated trace. Runs with no MS1 scans (e.g. QQQ MRM acquisitions, which are all MS2) emit no summary chromatograms rather than a misleading empty-typed one.

SRM/MRM transition chromatograms are intentionally not produced. OpenARaw decodes only an opaque mrm_channel_id, not the Q1/Q3 isolation windows an SRM chromatogram needs; recovering those would be new binary parsing rather than wiring up already-decoded data, which is out of scope here.

No downstream change is needed: OpenMassSpecCore's mzML writer (1.2.0) already calls iter_chromatograms and emits <chromatogramList>, writing chromatogram_type verbatim.

Testing

  • Added three self-contained unit tests in reader.rs (synthetic SpectrumRecords, no corpus needed): TIC/BPC are emitted over MS1 scans only with the correct accessions and aggregated values; empty result when there are no MS1 scans; empty MS1 scans contribute aligned zero points.
  • cargo test --all (45 pass), cargo clippy --all-targets -- -D warnings (clean), cargo fmt --all -- --check (clean). The corpus-gated conformance tests still pass.
  • Clean-room: correctness is argued only from the PSI-MS mzML/CV definitions and the self-consistency of TIC/BPC as aggregations of the already-decoded intensity arrays. No vendor software was used.

Note on the issue text

The filed issue text is a copy from another repo (it references "OpenTFRaw", crates/opentfraw/... paths, and a per-scan TIC/base-peak decode that already exists there). In OpenARaw those fields are not decoded per scan - the ScanRecord in raw/msscan.rs carries retention time, MS level, mass range and precursor fields, but not TIC or base-peak, and docs/format/01-msscan.md only tentatively labels the stride-284 offset-36 value as "TIC or related intensity metric". Rather than decode an unconfirmed field (a guess, and new binary parsing), I grounded the fix in this repo's actual code and derived the traces from the already-decoded MS1 intensities. The intent matches the cited Waters precedent (Sigilweaver/OpenWRaw#9, 574fe09): map what can be confidently derived, skip the rest.

https://claude.ai/code/session_01TLSifJpmaN7RvW3xi2uWgo

Override the trait default so total-ion-current and base-peak
chromatograms reach mzML output via OpenMassSpecCore's
<chromatogramList> writer. Both traces are aggregated from
already-decoded MS1 spectra (TIC = summed scan intensities,
BPC = per-scan base peak) with no new binary parsing, keeping them
self-consistent with the emitted spectra. Runs without MS1 scans
(e.g. QQQ MRM) emit nothing; SRM chromatograms are skipped because
the Q1/Q3 windows they require are not decoded.

Implements Sigilweaver#17.

Claude-Session: https://claude.ai/code/session_01TLSifJpmaN7RvW3xi2uWgo
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Implement iter_chromatograms so TIC/BPC/SRM chromatograms reach mzML output

1 participant